<template>
  <captcha-parent :class="classes" v-if="show">
    <slot name="loading">
      <img id="tianai-captcha-loading" class="loading" v-if="loading" src="@/assets/images/tianai/loading.gif" />
    </slot>

    <div id="tianai-captcha" class="tianai-captcha-slider" :style="styleCaptcha" v-if="!loading" @touchmove.passive="clearPreventDefault" @mousemove.passive="clearPreventDefault">
      <div class="slider-tip">
        <slot name="title">{{ title }}</slot>
      </div>
      <div class="content">
        <div class="bg-img-div" ref="img">
          <img id="tianai-captcha-slider-bg-img" :src="captchaData.captcha.backgroundImage" alt @load="backgroundImageloaded" />
          <canvas id="tianai-captcha-slider-bg-canvas"></canvas>
        </div>
        <div class="slider-img-div" id="tianai-captcha-slider-img-div" :style="styleImgDiv">
          <img id="tianai-captcha-slider-move-img" ref="templateImage" :src="captchaData.captcha.templateImage" alt />
        </div>
        <div class="tianai-captcha-tips" :class="classesTip">{{ tipMsg }}</div>
        <div class="refresh-btn" id="tianai-captcha-slider-refresh-btn" @click="reload"></div>
      </div>
      <div class="slider-move" :class="{ error: tipType === 0, success: tipType === 1 }">
        <div class="slider-move-track">
          <div class="tianai-captcha-slider-move-track-mask" :style="styleMoveMask"></div>
          <div class="slider-move-shadow"></div>
        </div>
        <slot name="sliderButton">
          <div class="slider-move-btn" :style="styleMoveBtn" @mousedown="onTouchstart" @touchstart="onTouchstart">
            <img class="slider-move-btn-img animation" :src="imageMovebtn" v-if="tipType === -1 && theme === THEMES.CFMOTO" />
            <img class="slider-move-btn-img" :src="imageMovebtn" v-else />
          </div>
        </slot>
      </div>
    </div>

    <template #bottom>
      <slot name="bottom">
        <div class="slider-bottom" v-if="theme === THEMES.TIANAI">
          <slot name="logo">
            <img class="logo" id="tianai-captcha-logo" src="@/assets/images/tianai/logo.png" v-if="theme === THEMES.TIANAI" />
          </slot>
          <div class="close-btn" id="tianai-captcha-slider-close-btn" @click="destroy" v-if="theme === THEMES.TIANAI"></div>
          <div class="refresh-btn" id="tianai-captcha-slider-refresh-btn" @click="reload"></div>
        </div>
      </slot>
    </template>
  </captcha-parent>
</template>
<script>
import { getCurrentCoordinate, drawBgImage, initConfig } from '@/utils';
import imgTianaiMoveBtn from '@/assets/images/tianai/move-btn.png';
import imgCfmotoMoveBtn from '@/assets/images/cfmoto/move-btn-arrow@2x.png';
import imgCfmotoMoveBtnError from '@/assets/images/cfmoto/move-btn-error@2x.png';
import imgCfmotoMoveBtnSuccess from '@/assets/images/cfmoto/move-btn-success@2x.png';
import CaptchaParent from './CaptchaParent.vue';

const THEMES = {
  TIANAI: 'tianai',
  CFMOTO: 'cfmoto',
};

export default {
  props: {
    modelValue: {
      type: Boolean,
      default: false,
    },
    title: {
      type: String,
      default: '拖动滑块完成拼图',
    },
    theme: {
      type: String,
      default: 'tianai',
    },
    showBottom: {
      type: Boolean,
      default: false,
    },
    styleConfig: {
      type: Object,
      default: () => {},
    },
    requestConfig: {
      type: Function,
      default: () => {},
    },
    requestCheck: {
      type: Function,
      default: () => {},
    },
    onLoaded: {
      type: Function,
      default: () => {},
    },
  },
  emits: ['update:modelValue'],
  components: { CaptchaParent },
  data() {
    return {
      THEMES,
      show: this.modelValue,
      loading: true,
      type: 'SLIDER',
      tipMsg: '',
      tipType: -1,
      captchaData: { captcha: {}, id: '' },
      currentCaptchaData: { currentCaptchaId: '', moveX: 0 },
    };
  },
  computed: {
    classes() {
      const theme = this.theme || '';
      if (theme === 'tianai') return '';
      if (theme === 'cfmoto') return 'cfmoto-captcha';
      return '';
    },
    classesTip() {
      const { tipType } = this;
      return { 'tianai-captcha-tips-error': tipType === 0, 'tianai-captcha-tips-success': tipType === 1, 'tianai-captcha-tips-on': tipType > -1 };
    },
    finalStyleConfig() {
      const defaultStyleConfig = { logoUrl: 'images/logo.png', moveTrackMaskBorderColor: '#00f4ab', moveTrackMaskBgColor: '#a9ffe5' };
      return { ...defaultStyleConfig, ...JSON.parse(JSON.stringify(this.styleConfig || {})) };
    },
    styleCaptcha() {
      const transform = `translateX(0px)`;

      if (this.loading) return {};
      return { transform };
    },
    styleMoveBtn() {
      const { moveX } = this.currentCaptchaData;
      const transform = `translate(${moveX}px, 0px)`;
      return { transform };
    },
    styleMoveMask() {
      const { moveX } = this.currentCaptchaData;
      const { moveTrackMaskBorderColor, moveTrackMaskBgColor } = this.finalStyleConfig;
      const width = `${moveX}px`;
      const borderColor = moveTrackMaskBorderColor;
      const backgroundColor = moveTrackMaskBgColor;
      if (this.theme === THEMES.TIANAI) {
        return { width, backgroundColor, borderColor };
      }
      return { width };
    },
    styleImgDiv() {
      const { moveX } = this.currentCaptchaData;
      const transform = `translate(${moveX}px, 0px)`;
      return { transform };
    },
    imageMovebtn() {
      const cfmotoImage = { '-1': imgCfmotoMoveBtn, 1: imgCfmotoMoveBtnSuccess, 0: imgCfmotoMoveBtnError }[this.tipType];
      const tianaiImage = { '-1': imgTianaiMoveBtn, 1: imgTianaiMoveBtn, 0: imgTianaiMoveBtn }[this.tipType];
      const backgroundImage = { tianai: tianaiImage, cfmoto: cfmotoImage }[this.theme];
      return backgroundImage;
    },
  },
  methods: {
    async init() {
      try {
        this.loading = true;
        this.tipType = -1;
        this.tipMsg = '';
        const captchaData = await this.requestConfig();
        this.captchaData = captchaData;
        this.currentCaptchaData = {};
        setTimeout(() => {
          this.onLoaded();
        }, 60);
      } catch (error) {
        throw new Error(error);
      } finally {
        setTimeout(() => {
          this.loading = false;
        }, 50);
      }
    },
    /**
     * 清除默认事件
     * @param event event
     */
    clearPreventDefault(event) {
      if (event.preventDefault) {
        event.preventDefault();
      }
    },
    /**
     * 手势松开||鼠标放开
     * @param {*} event
     */
    up(event) {
      this.destroyEvent();
      const coordinate = getCurrentCoordinate(event);
      this.currentCaptchaData.stopTime = new Date();
      let pageX = coordinate.x;
      let pageY = coordinate.y;
      const startX = this.currentCaptchaData.startX;
      const startY = this.currentCaptchaData.startY;
      const startTime = this.currentCaptchaData.startTime;
      const trackArr = this.currentCaptchaData.trackArr;

      const track = {
        x: pageX - startX,
        y: pageY - startY,
        type: 'up',
        t: new Date().getTime() - startTime.getTime(),
      };
      trackArr.push(track);
      if (this.requestCheck) {
        const currentCaptchaData = this.currentCaptchaData;
        const data = {
          bgImageWidth: currentCaptchaData.bgImageWidth,
          bgImageHeight: currentCaptchaData.bgImageHeight,
          sliderImageWidth: currentCaptchaData.sliderImageWidth,
          sliderImageHeight: currentCaptchaData.sliderImageHeight,
          startSlidingTime: currentCaptchaData.startTime,
          endSlidingTime: currentCaptchaData.stopTime,
          trackList: currentCaptchaData.trackArr,
        };
        // 清空
        const id = this.currentCaptchaData.currentCaptchaId;
        this.requestCheck(id, data, this);
      }
    },
    /**
     * 手势移动||鼠标移动
     * @param {*} event
     */
    move(event) {
      if (event.touches && event.touches.length > 0) {
        event = event.touches[0];
      }
      const coordinate = getCurrentCoordinate(event);
      let pageX = coordinate.x;
      let pageY = coordinate.y;
      const startX = this.currentCaptchaData.startX;
      const startY = this.currentCaptchaData.startY;
      const startTime = this.currentCaptchaData.startTime;
      const end = this.currentCaptchaData.end;
      const bgImageWidth = this.currentCaptchaData.bgImageWidth;
      const trackArr = this.currentCaptchaData.trackArr;
      let moveX = pageX - startX;
      const track = {
        x: pageX - startX,
        y: pageY - startY,
        type: 'move',
        t: new Date().getTime() - startTime.getTime(),
      };
      trackArr.push(track);
      if (moveX < 0) {
        moveX = 0;
      } else if (moveX > end) {
        moveX = end;
      }
      this.currentCaptchaData.moveX = moveX;
      this.currentCaptchaData.movePercent = moveX / bgImageWidth;
    },
    /**
     * 手势触碰||鼠标按下
     * @param {*} event
     */
    down(event) {
      const coordinate = getCurrentCoordinate(event);
      let startX = coordinate.x;
      let startY = coordinate.y;
      this.currentCaptchaData.startX = startX;
      this.currentCaptchaData.startY = startY;

      const pageX = this.currentCaptchaData.startX;
      const pageY = this.currentCaptchaData.startY;
      const startTime = this.currentCaptchaData.startTime;
      const trackArr = this.currentCaptchaData.trackArr;
      trackArr.push({
        x: pageX - startX,
        y: pageY - startY,
        type: 'down',
        t: new Date().getTime() - startTime.getTime(),
      });
      // pc
      window.addEventListener('mousemove', this.move);
      window.addEventListener('mouseup', this.up);
      // 手机端
      window.addEventListener('touchmove', this.move, false);
      window.addEventListener('touchend', this.up, false);
    },
    // 绑定事件
    onTouchstart(event) {
      this.down(event);
    },
    // 销毁事件
    destroyEvent() {
      window.removeEventListener('mousemove', this.move);
      window.removeEventListener('mouseup', this.up);
      window.removeEventListener('touchmove', this.move);
      window.removeEventListener('touchend', this.up);
    },
    reload() {
      this.init();
    },
    destroy() {
      if (this.currentCaptchaData.currentCaptchaId) {
        this.destroyEvent();
        this.loading = false;
        // window.currentCaptcha.el.css('transform', 'translateX(300px)');
        setTimeout(() => {
          this.show = false;
        }, 500);
      }
    },
    showTips(msg, type) {
      this.tipMsg = msg;
      this.tipType = type; //1:成功，0:失败
      setTimeout(() => {
        this.tipType = -1;
      }, 1000);
    },
    closeTips() {
      this.tipMsg = '';
      this.tipType = -1; //-1:隐藏
    },
    backgroundImageloaded(event) {
      const width = event.target.clientWidth;
      const height = event.target.clientHeight;
      const sliderWidth = this.$refs.templateImage.clientWidth;
      const sliderHeight = this.$refs.templateImage.clientHeight;
      const imgWidth = this.$refs.img.clientWidth;
      this.currentCaptchaData = initConfig(width, height, sliderWidth, sliderHeight, imgWidth - sliderWidth);
      this.currentCaptchaData.currentCaptchaId = this.captchaData.id;
      // 重组
      drawBgImage(this.captchaData.captcha, 'tianai-captcha-slider-bg-canvas', 'tianai-captcha-slider-bg-img', 50);
    },
  },
  created() {},
  mounted() {},
  beforeUnmount() {},
  watch: {
    modelValue: {
      immediate: true,
      handler(newValue) {
        this.show = newValue;
        if (newValue) {
          this.init();
        }
      },
    },
    show(newValue) {
      this.$emit('update:modelValue', newValue);
    },
  },
};
</script>
<style lang="scss" scoped>
#tianai-captcha.tianai-captcha-slider {
  z-index: 999;
  position: absolute;
  left: 0;
  top: 0;
  .content {
    width: 100%;
    height: 180px;
    position: relative;
    overflow: hidden;
  }
  .bg-img-div {
    width: 100%;
    height: 100%;
    position: absolute;
    transform: translate(0px, 0px);
    img {
      height: 100%;
      border-radius: 5px;
    }
  }
  .slider-img-div {
    height: 100%;
    position: absolute;
    transform: translate(0px, 0px);
    #tianai-captcha-slider-move-img {
      height: 100%;
    }
  }
  .slider-move {
    height: 34px;
    width: 100%;
    margin: 11px 0;
    position: relative;
  }
  .slider-move-track {
    position: relative;
    height: 32px;
    line-height: 32px;
    text-align: center;
    background: #f5f5f5;
    color: #999;
    transition: 0s;
    font-size: 14px;
    box-sizing: content-box;
    border: 1px solid #f5f5f5;
    border-radius: 4px;
  }
  .refresh-btn,
  .close-btn {
    display: inline-block;
  }
  .slider-move {
    line-height: 38px;
    font-size: 14px;
    text-align: center;
    white-space: nowrap;
    color: #88949d;
    -moz-user-select: none;
    -webkit-user-select: none;
    user-select: none;
    filter: opacity(0.8);
  }
  .slider-move .slider-move-btn {
    transform: translate(0px, 0px);
    position: absolute;
    top: -6px;
    left: 0;
    width: 63px;
    height: 45px;
    background-color: #fff;
    background-repeat: no-repeat;
    background-size: contain;
    border-radius: 5px;
    &-img {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
    }
  }
  .slider-tip {
    margin-bottom: 5px;
    font-weight: bold;
    font-size: 15px;
    line-height: normal;
    color: black;
  }
  .slider-move-btn:hover {
    cursor: pointer;
  }
  user-select: none;
}
</style>
<style lang="scss" scoped>
#tianai-captcha-parent.cfmoto-captcha :deep() {
  box-sizing: border-box;
  padding: 15px;
  width: 335px;
  height: 283px;
  background: #ffffff;
  border-radius: 8px;
  // .tianai-captcha-box {
  //   box-sizing: border-box;
  //   padding: 15px;
  // }
  .tianai-captcha-slider {
    width: 100%;
    .slider-tip {
      margin-bottom: 15px;
      line-height: 1.5;
      font-weight: 500;
      font-size: 16px;
      color: #151e21;
    }
    .content {
      height: 154px;
      .refresh-btn {
        position: absolute;
        top: 4px;
        right: 4px;
        width: 24px;
        height: 24px;
        background-repeat: no-repeat;
        background-repeat: center top;
        background-size: 24px 24px;
        background-image: url('@/assets/images/cfmoto/btn-refresh@2x.png');
      }
    }
    .slider-move {
      box-sizing: border-box;
      margin: 15px 0 0;
      width: 305px;
      height: 48px;
      background: #f5f5f5;
      border-radius: 4px;
      border: 1px solid #cccccc;
      &-track {
        height: 100%;
        .tianai-captcha-slider-move-track-mask {
          height: 100%;
          background: #cbf4ff;
          border-radius: 4px;
          border: 1px solid #00bdf1;

          &.error {
          }
          &.success {
            background: #cbf4ff;
            border: 1px solid #00bdf1;
          }
        }
      }
      &-btn {
        position: absolute;
        top: -1px;
        left: -1px;
        width: 48px;
        height: 48px;
        background: #ffffff;
        box-shadow: 0px 1px 5px 0px rgba(0, 143, 220, 0.19);
        border-radius: 4px;

        &-img {
          position: absolute;
          left: 50%;
          top: 50%;
          width: 18px;
          height: 18px;
          margin-left: -9px;
          margin-top: -9px;

          &.animation {
            @keyframes myanimation {
              0% {
                transform: translateX(-40%);
              }
              40% {
                transform: translateX(40%);
              }
              50% {
                transform: translateX(60%);
              }
              60% {
                transform: translateX(40%);
              }
              100% {
                transform: translateX(-40%);
              }
            }
            animation: myanimation 1.5s ease-in-out infinite;
          }
        }
      }
      &.success {
        .tianai-captcha-slider-move-track-mask {
          background: #cbf4ff;
          border-color: #00bdf1;
        }
        .slider-move-btn {
          background: none;
          box-shadow: none;
          &-img {
            animation: none;
            margin-top: -29px;
            margin-left: -29px;
            min-width: 58px;
            height: 58px;
          }
        }
      }
      &.error {
        .tianai-captcha-slider-move-track-mask {
          background: #ffe0e0;
          border-color: #ff1919;
        }
        .slider-move-btn {
          background: none;
          box-shadow: none;
          &-img {
            animation: none;
            margin-top: -29px;
            margin-left: -29px;
            min-width: 58px;
            height: 58px;
          }
        }
      }
    }
  }

  #tianai-captcha-slider-bg-canvas {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    border-radius: 5px;
  }
}
</style>
